package com.xjrsoft.module.app.service.impl;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xjrsoft.common.page.ConventPage;
import com.xjrsoft.common.page.PageOutput;
import com.xjrsoft.core.constant.RedisKeyConstants;
import com.xjrsoft.core.secure.XjrUser;
import com.xjrsoft.core.secure.utils.SecureUtil;
import com.xjrsoft.core.tool.node.ForestNodeMerger;
import com.xjrsoft.core.tool.node.INode;
import com.xjrsoft.core.tool.utils.BeanUtil;
import com.xjrsoft.core.tool.utils.CollectionUtil;
import com.xjrsoft.core.tool.utils.StringPool;
import com.xjrsoft.core.tool.utils.StringUtil;
import com.xjrsoft.module.app.dto.AppFunctionListDto;
import com.xjrsoft.module.app.entity.XjrAppFunction;
import com.xjrsoft.module.app.entity.XjrAppFunctionButton;
import com.xjrsoft.module.app.entity.XjrAppFunctionColumn;
import com.xjrsoft.module.app.entity.XjrAppFunctionForm;
import com.xjrsoft.module.app.mapper.XjrAppFunctionMapper;
import com.xjrsoft.module.app.service.IXjrAppFunctionButtonService;
import com.xjrsoft.module.app.service.IXjrAppFunctionColumnService;
import com.xjrsoft.module.app.service.IXjrAppFunctionFormService;
import com.xjrsoft.module.app.service.IXjrAppFunctionService;
import com.xjrsoft.module.app.utils.FunctionUtil;
import com.xjrsoft.module.app.vo.AppFunctionVo;
import com.xjrsoft.module.app.vo.FunctionFormVo;
import com.xjrsoft.module.app.vo.FunctionOtherVo;
import com.xjrsoft.module.base.entity.XjrBaseAuthorize;
import com.xjrsoft.module.base.entity.XjrBaseRole;
import com.xjrsoft.module.base.service.IXjrBaseAuthorizeService;
import com.xjrsoft.module.base.service.IXjrBaseRoleService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * APP端功能模块管理表 服务实现类
 * </p>
 *
 * @author jobob
 * @since 2021-02-23
 */
@Service
@AllArgsConstructor
public class XjrAppFunctionServiceImpl extends ServiceImpl<XjrAppFunctionMapper, XjrAppFunction> implements IXjrAppFunctionService {


    private final IXjrBaseRoleService roleService;

    private final IXjrBaseAuthorizeService authorizeService;

    private final IXjrAppFunctionButtonService buttonService;

    private final IXjrAppFunctionColumnService columnService;

    private final IXjrAppFunctionFormService formService;

    @Override
    public List<AppFunctionVo> getAppModuleForCurrentUser() {
        List<XjrAppFunction> appFunctionList = new ArrayList<>();
        //如果用户为管理员获取所有菜单
        if (SecureUtil.isAdminUser()) {
            appFunctionList = getAppModuleList();
        } else {
            appFunctionList = getAuthModuleForObject(SecureUtil.getUserId());
        }
        if (CollectionUtil.isNotEmpty(appFunctionList)) {
            return BeanUtil.copyList(appFunctionList, AppFunctionVo.class);
        }
        return null;
    }

    @Override
    public List<XjrAppFunction> getAuthFunctionListByObject(String objectId, Integer objectType) {
        List<XjrBaseAuthorize> authorizeList = authorizeService.list(Wrappers.<XjrBaseAuthorize>query().lambda()
                .eq(XjrBaseAuthorize::getObjectId, objectId)
                .eq(XjrBaseAuthorize::getObjectType, objectType)
                .eq(XjrBaseAuthorize::getItemType, 5));
        if (CollectionUtil.isNotEmpty(authorizeList)) {
            List<String> itemList = authorizeList.stream().map(authorize -> authorize.getItemId()).collect(Collectors.toList());
            return this.list(Wrappers.<XjrAppFunction>query().lambda().in(XjrAppFunction::getId, itemList));
        }
        return new ArrayList<>();
    }

    @Override
    public List<AppFunctionVo> getAllAppModule() {
        List<XjrAppFunction> xjrAppFunctions = getAppModuleList();
        if(xjrAppFunctions!=null&&xjrAppFunctions.size()>0) {
            return BeanUtil.copyList(xjrAppFunctions, AppFunctionVo.class);
        }
        return null;
    }

    @Override
    public List<AppFunctionVo> getAppModuleByType(String type) {
        if(!StringUtils.isEmpty(type)) {
            List<XjrAppFunction> xjrAppFunctions = this.list(Wrappers.<XjrAppFunction>query().lambda().eq(XjrAppFunction::getEnabledMark, 1).eq(XjrAppFunction::getType, type).orderByAsc(XjrAppFunction::getSortCode));
            if(xjrAppFunctions!=null&&xjrAppFunctions.size()>0){
                return BeanUtil.copyList(xjrAppFunctions, AppFunctionVo.class);
            }
        }
        return null;
    }

    @Override
    public PageOutput<AppFunctionVo> getPageList(AppFunctionListDto listDto) {
        String keyword = listDto.getKeyword();
        if (!StringUtil.isEmpty(keyword)) {
            keyword = StringPool.PERCENT + keyword + StringPool.PERCENT;
        }
        String orderField = listDto.getOrderfield();
        if (StringUtil.isEmpty(orderField)) {
            listDto.setOrderfield("f.F_SortCode");
        } else {
            listDto.setOrderfield("f." + orderField);
        }
        IPage<AppFunctionVo> page = ConventPage.getPage(listDto);
        List<AppFunctionVo> resultList = this.baseMapper.getPageList(listDto.getType(), keyword, page);
        return ConventPage.getPageOutput(page.getTotal(), resultList);
    }

    @Override
    public List<XjrAppFunction> getAuthFuncForCurUser(String type) {
        XjrUser user = SecureUtil.getUser();
        if (user.isAdminUser()) {
            return this.list(Wrappers.<XjrAppFunction>query().lambda()
                    .eq(!StringUtil.isEmpty(type), XjrAppFunction::getType, type)
                    .eq(XjrAppFunction::getEnabledMark, 1)
                    .orderByAsc(XjrAppFunction::getSortCode));
        } else {
            return this.baseMapper.getAuthFuncList(user.getUserId(), SecureUtil.getRoleIdList(), type);
        }
    }

    @Override
    @Transactional
    public boolean saveAppFunction(XjrAppFunction function, List<XjrAppFunctionButton> buttonList, List<XjrAppFunctionColumn> columnList, List<XjrAppFunctionForm> formList) {
        String functionId = IdWorker.get32UUID();
        function.setId(functionId);
        if (function.getIsSystem() == null) {
            function.setIsSystem(1);
        }

        if (CollectionUtil.isNotEmpty(buttonList)) {
            buttonList.stream().forEach(button -> button.setFunctionId(functionId));
        }
        if (CollectionUtil.isNotEmpty(columnList)) {
            columnList.stream().forEach(column -> column.setFunctionId(functionId));
        }
        if (CollectionUtil.isNotEmpty(formList)) {
            formList.stream().forEach(form -> form.setFunctionId(functionId));
        }
        boolean isSuccess = this.save(function);
        if (isSuccess) {
            buttonService.saveBatch(buttonList);
            columnService.saveBatch(columnList);
            formService.saveBatch(formList);
        }

        return isSuccess;
    }

    @Override
    public boolean updateAppFunction(String id, XjrAppFunction function, List<XjrAppFunctionButton> buttonList, List<XjrAppFunctionColumn> columnList, List<XjrAppFunctionForm> formList) {
        function.setId(id);
        if (CollectionUtil.isNotEmpty(buttonList)) {
            buttonList.stream().forEach(button -> button.setFunctionId(id));
        }
        if (CollectionUtil.isNotEmpty(columnList)) {
            columnList.stream().forEach(column -> column.setFunctionId(id));
        }
        if (CollectionUtil.isNotEmpty(formList)) {
            formList.stream().forEach(form -> form.setFunctionId(id));
        }
        boolean isSuccess = this.updateById(function);
        if (isSuccess) {
            buttonService.remove(Wrappers.<XjrAppFunctionButton>query().lambda().eq(XjrAppFunctionButton::getFunctionId, id));
            buttonService.saveBatch(buttonList);

            columnService.remove(Wrappers.<XjrAppFunctionColumn>query().lambda().eq(XjrAppFunctionColumn::getFunctionId, id));
            columnService.saveBatch(columnList);

            formService.remove(Wrappers.<XjrAppFunctionForm>query().lambda().eq(XjrAppFunctionForm::getFunctionId, id));
            formService.saveBatch(formList);
        }
        return isSuccess;
    }

    @Override
    public List<FunctionOtherVo> getFunctionSubAuth() {
        List<FunctionOtherVo> resultList = new ArrayList<>();
        List<XjrAppFunction> authFunctionList = getAuthFuncForCurUser(null);
        List<String> authCode = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(authFunctionList)) {
            List<String> authFuncIdList = authFunctionList.stream().map(authFunc -> authFunc.getId()).collect(Collectors.toList());
            List<XjrAppFunctionButton> buttonList = buttonService.getAuthButtonForCurUser(authFuncIdList);
            List<XjrAppFunctionColumn> columnList = columnService.getAuthColumnForCurUser(authFuncIdList);
            List<XjrAppFunctionForm> formList = formService.getAuthFormForCurUser(authFuncIdList);
            for (XjrAppFunction function : authFunctionList) {
                FunctionOtherVo otherVo = new FunctionOtherVo();
                otherVo.setFunctionId(function.getId());

                for (XjrAppFunctionButton button : buttonList) {
                    if (StringUtil.equalsIgnoreCase(button.getFunctionId(), function.getId())) {
                        otherVo.getButtonCodeList().add(button.getEnCode());
                        authCode.add(button.getEnCode());
                    }
                }

                for (XjrAppFunctionColumn column : columnList) {
                    if (StringUtil.equalsIgnoreCase(column.getFunctionId(), function.getId())) {
                        otherVo.getColumnCodeList().add(column.getEnCode());
                    }
                }

                List<FunctionFormVo> formTreeVoList = ForestNodeMerger.merge(BeanUtil.copyList(formList, FunctionFormVo.class));
                for (FunctionFormVo form : formTreeVoList) {
                    if (StringUtil.equalsIgnoreCase(form.getFunctionId(), function.getId())) {
                        List<INode> children = form.getChildren();
                        String enCode = form.getEnCode();
                        if (CollectionUtil.isNotEmpty(children)) {
                            Set<String> tabFields = new LinkedHashSet<>();
                            for (INode child : children) {
                                FunctionFormVo tabField = (FunctionFormVo) child;
                                tabFields.add(tabField.getEnCode());
                            }
                            Map<String, Set<String>> formFullMap = new HashMap<>(4);
                            formFullMap.put(enCode, tabFields);
                            otherVo.getFormCodeList().add(formFullMap);
                        } else {
                            otherVo.getFormCodeList().add(enCode);
                        }
                    }
                }
                resultList.add(otherVo);
            }
        }
        SaSession tokenSession = StpUtil.getTokenSession();
        // 将用户的权限存入到redis
        tokenSession.set(RedisKeyConstants.CACHE_APP_AUTH_CODE_KEY, authCode);

        return resultList;
    }

    //获取用户菜单信息
    private List<XjrAppFunction> getAuthModuleForObject(String objectId) {
        List<String> roleIds = new ArrayList<>();
        //获取用户角色信息
        List<XjrBaseRole> roleList = roleService.getAppRolesByUserId(objectId);
        if (CollectionUtil.isNotEmpty(roleList)) {
            roleList.stream().forEach(role -> roleIds.add(role.getRoleId()));
        }
        return this.getAppModuleOfAuth(roleIds);
    }

    private List<XjrAppFunction> getAppModuleOfAuth(List<String> roleIds) {
        if (CollectionUtil.isNotEmpty(roleIds)) {
            LambdaQueryWrapper<XjrBaseAuthorize> queryWrapper = Wrappers.<XjrBaseAuthorize>query().lambda().eq(XjrBaseAuthorize::getItemType, 5).eq(XjrBaseAuthorize::getObjectType, 1).in(XjrBaseAuthorize::getObjectId, roleIds);
            //获取用户权限信息
            List<XjrBaseAuthorize> authorizeList = authorizeService.list(queryWrapper);
            if (CollectionUtil.isNotEmpty(authorizeList)) {
                //获取所有菜单id
                Set<String> itemIds = authorizeList.stream().map(XjrBaseAuthorize::getItemId).collect(Collectors.toSet());
                LambdaQueryWrapper<XjrAppFunction> functionLambdaQueryWrapper = Wrappers.<XjrAppFunction>query().lambda().eq(XjrAppFunction::getEnabledMark, 1).in(XjrAppFunction::getId, itemIds).orderByAsc(XjrAppFunction::getSortCode);
                //获取所有菜单信息
                List<XjrAppFunction> appFunctions = this.list(functionLambdaQueryWrapper);
                return appFunctions;
            }
        }
        return null;
    }

    //获取所有菜单
    @Override
    public List<XjrAppFunction> getAppModuleList() {
        return this.list(Wrappers.<XjrAppFunction>query().lambda().eq(XjrAppFunction::getEnabledMark, 1).orderByAsc(XjrAppFunction::getSortCode));
    }

    @Override
    @Transactional
    public boolean saveFunction(XjrAppFunction function,
                                String prefixEnCode,
                                List<Map<String, Object>> buttonMapList,
                                List<Map<String, Object>> columnMapList,
                                List<Map<String, Object>> formMapList) {
        String functionId = function.getId();
        if (StringUtils.isEmpty(functionId)) {
            functionId = IdWorker.get32UUID();
            function.setId(functionId);
        }
        if (function.getIsSystem() == null) {
            function.setIsSystem(1);
        }
        boolean isSuccess = this.save(function);
        // 按钮
        if (isSuccess && CollectionUtil.isNotEmpty(buttonMapList)) {
            buttonService.saveBatch(FunctionUtil.buildButtonEntities(functionId, prefixEnCode,  buttonMapList));
        }
        // 列表字段
        if (isSuccess && CollectionUtil.isNotEmpty(columnMapList)) {
            columnService.saveBatch(FunctionUtil.buildColumnEntities(functionId, columnMapList));
        }
        // 表单字段
        if (isSuccess && CollectionUtil.isNotEmpty(formMapList)) {
            formService.saveBatch(FunctionUtil.buildFormEntities(functionId, formMapList));
        }

        return isSuccess;
    }
}
